package org.budo.dubbo.protocol.http;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.rpc.Exporter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.protocol.AbstractExporter;

/**
 * @author lmw
 * @see org.budo.dubbo.protocol.http.dispatcher.servlet.BudoDubboHttpProtocolDispatcherServlet
 * @see org.budo.dubbo.protocol.http.BudoDubboHttpInvoker
 */
public class BudoDubboHttpProtocol implements Protocol {
    /**
     * 没用，依赖Servlet作为入口，本身并不监听端口
     */
    private static final int PORT = 86;

    private static final Logger log = LoggerFactory.getLogger(BudoDubboHttpProtocol.class);

    private static BudoDubboHttpProtocol INSTANCE = null;

    private final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();

    public static BudoDubboHttpProtocol getInstance() {
        synchronized (BudoDubboHttpProtocol.class) {
            return INSTANCE;
        }
    }

    /**
     * 应该是单例的吧，实例化时给静态变量赋值
     */
    public BudoDubboHttpProtocol() {
        synchronized (BudoDubboHttpProtocol.class) {
            log.warn("#37 BudoDubboHttpProtocol init, INSTANCE=" + INSTANCE + ", classLoader=" + this.getClass().getClassLoader() + ", this=" + this);
            INSTANCE = this;
        }
    }

    /**
     * 默认端口，其实没用
     */
    public int getDefaultPort() {
        return PORT;
    }

    public Map<String, Exporter<?>> getExporterMap() {
        return this.exporterMap;
    }

    /**
     * @see com.alibaba.dubbo.rpc.protocol.http.HttpProtocol#doExport(T, Class<T>,
     *      URL)
     */
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        String exporterKey = invoker.getUrl().getServiceInterface();

        Exporter<T> exporter = (Exporter<T>) this.getExporterMap().get(exporterKey);
        if (null != exporter) {
            return exporter;
        }

        return this.doExport(invoker);
    }

    private <T> Exporter<T> doExport(Invoker<T> invoker) {
        final String exporterKey = invoker.getUrl().getServiceInterface();

        // TODO 防御性检查，避免接口中有同名方法
        Exporter<T> exporter = new AbstractExporter<T>(invoker) {
            public void unexport() {
                super.unexport();

                BudoDubboHttpProtocol.this.getExporterMap().remove(exporterKey);
            }
        };

        // doExport
        this.getExporterMap().put(exporterKey, exporter);

        return exporter;
    }

    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        BudoDubboHttpInvoker<T> invoker = new BudoDubboHttpInvoker<T>(type, url);

        log.info("#92 refer, type=" + type + ", url=" + url + ", invoker=" + invoker);
        return invoker;
    }

    public void destroy() {
        log.info("#88 BudoDubboHttpProtocol.destroy(), this=" + this);
    }

    public String toString() {
        return super.toString() + ", exporterMap=" + this.getExporterMap();
    }
}
